---
title: Chains and Steps
description: Chains and Steps are used to create multi-step prompts that can interact with the AI model in stages.
---

## Overview

Chains in PromptL allow you to break complex workflows into smaller, manageable steps. Each step generates a response, which can then be used in subsequent steps. This approach improves the model's ability to perform complex tasks and provides greater control over dynamic conversations.

With Chains, you can:

- Process tasks incrementally to guide the model step-by-step.
- Store and reuse intermediate results dynamically.
- Customize step-specific configurations for more efficient execution.
- Isolate steps to minimize context overhead or confusion.

---

## Syntax

Define steps in your prompt using the `<step>` tag. The engine pauses after each step, waits for the model's response, and adds it as an assistant message before continuing.

### Basic Syntax

```xml
<step>
  Analyze the following text and identify the main idea:

  <user>
    "The quick brown fox jumps over the lazy dog."
  </user>
</step>

<step>
  Now, summarize the identified main idea in one sentence.
</step>
```

### Step with Custom Configuration

Override the default configuration by adding attributes to the `<step>` tag:

```tsx
<step model="gpt-3.5-turbo" temperature={{0.5}}>
  Rewrite the following paragraph in simpler language:

  <user>
    "Quantum mechanics explains the behavior of particles on a microscopic scale."
  </user>
</step>
```

---

## Advanced Features

### Storing Step Responses

You can store the text response of a step in a variable using the `as` attribute. This allows you to reuse the response in later steps or logic blocks.

```xml
<step as="analysis">
  Is this statement correct? {{ statement }}
  Respond only with "correct" or "incorrect".
</step>

{{ if analysis == "correct" }}
  Provide additional details about why the statement is correct.
{{ else }}
  Explain why the statement is incorrect and provide the correct answer.
{{ endif }}
```

#### Parse Step Responses as JSON

The response of a step will be automatically parsed as JSON if the JSON output schema is defined.

```xml
<step as="analysis" schema={{{type: "object", properties: {correct: {type: "boolean"}}, required: ["correct"]}}}>
  Is this statement correct? {{ statement }}
  Respond only with "correct: true" or "correct: false" in a JSON object.
</step>

{{ if analysis.correct }}
  Provide additional details about why the statement is correct.
{{ else }}
  Explain why the statement is incorrect and provide the correct answer.
{{ endif }}
```

[Learn more about JSON Output](/guides/prompt-manager/json-output).

### Storing Raw Messages

Some providers will return additional metadata along with the response. To store the entire message object, instead of just the text response (e.g., role, content, and additional metadata), use the `raw` attribute:

```xml
<step raw="detailedMessage">
  Summarize the following text:
  {{ text }}
</step>
```

The raw response will return an object with the full message details, which contains the `role`, `content`, and other metadata provided by the model.
The `content` attribute will always be defined as an array of content objects, which can include text, images, tool calls and any other types of content returned by the LLM.

```json
{
  "role": "assistant",
  "content": [
    {
      "type": "text",
      "text": "This is a summary of the text."
    },
    {
      "type": "tool-call",
      "toolCallId": "tool-123",
      "toolName": "store-summary",
      "toolArguments": {
        "summary": "This is a summary of the text."
      }
    }
  ]
}
```

---

### Isolating Steps

Use the `isolated` attribute to prevent a step from inheriting context from previous steps. This can reduce unnecessary costs or confusion for the model.

```xml
<step isolated as="summary1">
  Summarize the following text:
  {{ text1 }}
</step>

<step isolated as="summary2">
  Summarize the following text:
  {{ text2 }}
</step>

<step>
  Compare these summaries and provide a conclusion:
  {{ summary1 }}
  {{ summary2 }}
</step>
```

In this example, the final step does not need to conside the full texts used in previous steps, so isolating the first two steps can help reduce context overhead, resulting in cheaper and more efficient processing.

---

### Limiting the number of steps

<Note>This feature is only available on the Latitude platform.</Note>

Latitude automatically applies a `maxSteps` limit of 20 to all prompts with configuration. This helps prevent infinite loops or excessive processing in long chains when creating complex workflows with steps within loops.

You can customize this limit by explicitly setting the `maxSteps` attribute on the main configuration section:

```xml
---
maxSteps: 5
---

{{ for item in list }}
  <step>
    ...
  </step>
{{ endfor }}
```

Read more about this configuration in the [Latitude Prompt Configuration](/guides/prompt-manager/configuration#maxsteps) guide.

---

## Real-World Use Cases

### Multi-Step Workflow

Chains are ideal for breaking down tasks like:

1. Analyzing data.
2. Generating intermediate results.
3. Combining results for a final output.

```xml
<step as="analysis">
  Analyze the following data and provide key insights:
  {{ data }}
</step>

<step>
  Based on the insights:
  {{ analysis }}
  Provide recommendations for improvement.
</step>
```

### Decision Trees

Use logic to adapt workflows based on intermediate results:

```xml
<step as="classification">
  Classify this document into one of the following categories: A, B, or C.
</step>

{{ if classification == "A" }}
<step>
  Generate detailed content for Category A.
</step>
{{ else if classification == "B" }}
<step>
  Generate detailed content for Category B.
</step>
{{ else }}
<step>
  Generate detailed content for Category C.
</step>
{{ endif }}
```

---

## Implementation

To execute chains, use the `Chain` class. The chain evaluates the prompt step-by-step, waiting for the model's response at each step.

To run a step, execute the `step` method of the chain instance. The first time `step` is called, it should not include any arguments. Subsequent calls must always pass the model response message from the previous step.

### Example: Using the Chain Class

```javascript
import { Chain } from 'promptl-ai';
import OpenAI from 'openai';

// Initialize the OpenAI client
const client = new OpenAI();

// Generate a response based on step messages and configuration
async function generateResponse({ config, messages }) {
  const response = await client.chat.completions.create({
    model: "gpt-4o-mini",
    ...config,
    messages,
  });
  return response.choices[0].message;
}

// Create a new chain
const chain = new Chain({
  prompt: '...', // Your PromptL prompt as a string
  parameters: {...} // Your prompt parameters
});

// Process the chain step-by-step
let result = await chain.step(); // The first step does not require any arguments
let lastResponse;

while (!result.completed) {
  lastResponse = await generateResponse(result);
  result = await chain.step(lastResponse); // Pass the model response to the next step
}

console.log('Final Output:', lastResponse.content);
```

---

## Debugging Chains

1. **Log Intermediate Steps**:
   - Use the `raw` attribute to inspect full responses for debugging.
2. **Handle Errors Gracefully**:
   - Implement fallback logic for unexpected responses or failures.
3. **Test Edge Cases**:
   - Ensure your chains handle empty inputs, invalid configurations, or incomplete data.

---

## Summary

Chains and Steps provide powerful tools for breaking complex tasks into manageable parts. With features like custom configurations, variable storage, and step isolation, you can design robust, dynamic workflows tailored to any use case.
